package com.basejace.core.base;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import com.basejace.core.R;
import com.jfinal.aop.Before;
import com.jfinal.core.Controller;
import com.jfinal.log.Log;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.Table;
import com.jfinal.plugin.activerecord.TableMapping;
import com.jfinal.plugin.activerecord.tx.Tx;

public class BaseController extends Controller {
	protected Log log = Log.getLog(this.getClass());
	
	public final String CONTENT = "content.jsp";
	public final String LIST = "list.jsp";
	public final String MSG = "message";
	
	protected Class<? extends Model> modelClass;
	protected String modelSimpleName;
	protected Model<?> modelEntity;
	
	
	/**
	 * 默认会使用的Model为 该Controller的名称上的model
	 * 例如 UserRoleController 的默认Model名称为 UserRole
	 */
	public BaseController() {
	}
	
	
	public BaseController(Class<? extends Model> modelClass, String modelSimpleName) {
		this.modelClass = modelClass;
		this.modelSimpleName = modelSimpleName;
	}

	/********************************下面CRUD操作*********************************************/
	
	public void show() {
		try {
			this.beforeShow();
			
		} catch (Exception e) {
			e.printStackTrace();
			this.setAttr(MSG, e.getMessage());
		}
		render(LIST);
		
	}
	
	public void list() {
		try {
			this.beforeList();
			Map<String, String[]> paramMap = getParaMap();
			
			
			
			this.afterList();
		} catch (Exception e) {
			e.printStackTrace();
			this.setAttr(MSG, e.getMessage());
		}
	}
	
	

	
	public void view() {
		try {
			Object[] primaryKeys = getPK(getPara(R.Key.PK)); //可能有多组主键
			//this.modelEntity = this.getModelEntity().dao().findById(primaryKeys[0]);
			if( primaryKeys[0] instanceof Object[] )
				this.modelEntity = getModelClass().newInstance().dao().findById((Object[])primaryKeys[0]);
			else
				this.modelEntity = getModelClass().newInstance().dao().findById(primaryKeys[0]);
			
			//this.modelEntity = getModelClass().newInstance().dao().findById(primaryKeys[0] instanceof Object[] ? (Object[])primaryKeys[0] : primaryKeys[0]);
//			this.setAttr(this.getModelSimpleName(), modelEntity);
//			下面这句也可以执行查询
//			Record record = Db.findById(getTableName(getModelClass()), getTablePrimaryKey(getModelClass()), primaryKeys[0]);
//			Model m = getModelClass().newInstance().put(record);

			this.setAttr(getModelSimpleName(), this.modelEntity);
			this.beforeView();
		} catch (Exception e) {
			e.printStackTrace();
			this.setAttr(MSG, "查看信息失败：" + e.getMessage());
		}
		this.setAttr(R.Key.IS_NEW, R.Const.FALSE);
		this.setAttr(R.Key.IS_EDIT, R.Const.FALSE);
		render(CONTENT);
	}
	
	public void edit() {
		try {
			Object[] primaryKeys = getPK(getPara(R.Key.PK)); //可能有多组主键
			//this.modelEntity = this.getModelEntity().dao().findById(primaryKeys[0]);
			
			//this.modelEntity = getModelClass().newInstance().dao().findById(primaryKeys[0] instanceof Object[] ? (Object[])primaryKeys[0] : primaryKeys[0]);
			if( primaryKeys[0] instanceof Object[] )
				this.modelEntity = getModelClass().newInstance().dao().findById((Object[])primaryKeys[0]);
			else
				this.modelEntity = getModelClass().newInstance().dao().findById(primaryKeys[0]);
//			下面这两句也可以执行查询
//			Record record = Db.findById(getTableName(getModelClass()), getTablePrimaryKey(getModelClass()), primaryKeys[0]);
//			Model m = getModelClass().newInstance().put(record);

			this.setAttr(getModelSimpleName(), this.modelEntity);
			this.beforeEdit();
		} catch (Exception e) {
			//e.printStackTrace();
			this.setAttr(MSG, e.getMessage());
		}
		this.setAttr(R.Key.IS_NEW, R.Const.FALSE);
		this.setAttr(R.Key.IS_EDIT, R.Const.TRUE);
		render(CONTENT);
	}
	
	public void add() {
		try {
			this.beforeAdd();
			
		} catch (Exception e) {
			e.printStackTrace();
			this.setAttr(MSG, e.getMessage());
		}
		this.setAttr(R.Key.IS_NEW, R.Const.TRUE);
		this.setAttr(R.Key.IS_EDIT, R.Const.TRUE);
		render("content.jsp");
	}

	
	/**
	 * 支持批量根据主键删除;
	 * 每组主键用 @ 隔开， 复合主键中间用逗号隔开
	 * 页面传参数示例 ：
	 * 单主键的 /delete?PK=123123,423423
	 * 复合主键../delete?PK=131241311,fsadfasdf@12324324,fasfasdf
	 */
	@Before(Tx.class)
	public void delete() {
		try {
			this.beforeDelete();
			Object[] primaryKeys = getPK(getPara(R.Key.PK)); //可能有多组主键
			for (int i=0; i<primaryKeys.length; i++) {
				if (primaryKeys[i] instanceof Object[])
					this.getModelEntity().deleteById((Object[])primaryKeys[i]);
				else
					this.getModelEntity().deleteById(primaryKeys[i]);
//				或者使用下面这句
//				Db.deleteById(getTableName(getModelClass()), getTablePrimaryKey(getModelClass()), primaryKeys[i]);
			}
			this.afterDelete();
			setAttr(MSG, "删除成功");
		} catch (Exception e) {
			e.printStackTrace();
			setAttr("message", "删除失败：" + e.getMessage());
		}
		render(LIST);
	}
	
	public void save() {
		String isNew = this.getPara(R.Key.IS_NEW);
		this.modelEntity = getModel(getModelClass(), getModelSimpleName(), true); //忽略转换错误
		
		try {
			if (R.Const.TRUE.equals(isNew)) {
				//这里是新建
				this.beforeSave();
				modelEntity.save();
				this.afterSave();
				this.setAttr(MSG, "新增成功");
			} else {
				//这里是更新
				this.beforeUpdate();
				modelEntity.update();
				this.afterUpdate();
				this.setAttr(MSG, "修改成功");
			}
		} catch (Exception e) {
			e.printStackTrace();
			this.setAttr(MSG, e.getMessage());
		}
		this.setAttr(getModelSimpleName(), this.modelEntity);
		this.setAttr(R.Key.IS_EDIT, R.Const.FALSE);
		this.setAttr(R.Key.IS_NEW, R.Const.FALSE);
		
		render(CONTENT);
	}
	
	
	public void beforeShow()throws Exception {}
	public void beforeList()throws Exception {}
	public void afterList()throws Exception {}
	public void beforeView()throws Exception {}
	public void beforeEdit()throws Exception {}
	public void beforeAdd()throws Exception {}
	
	
	/**
	 * 子类可实现在delete前执行一些逻辑
	 */
	protected void beforeDelete()throws Exception {}
	/**
	 * 子类可实现在delete后执行一些逻辑
	 */
	protected void afterDelete()throws Exception {}
	public void beforeSave()throws Exception {/*可以设置主键等getModelEntity().set("", "")*/}
	public void afterSave()throws Exception {}
	public void beforeUpdate()throws Exception {}
	public void afterUpdate()throws Exception {}
	/**
	 * 默认设置
	 * @return
	 */
	public Class<? extends Model> getModelClass() {
		try {
			if (modelClass == null) {
				String controllerClass = this.getClass().getName();
				System.out.println("===================" + controllerClass);
				//获取的Model类名 com.basejace.common.model
				String modelClassName = StringUtils.substringBeforeLast(controllerClass, "Controller").replaceAll(
						"\\.controller\\.", ".model.");
				modelClass = (Class<? extends Model>) Class.forName(modelClassName).newInstance().getClass();
			}
		} catch (Exception e) {
			this.setAttr("message", "获取Model class异常:" + e.getMessage());
			e.printStackTrace();
		}
		return modelClass;
	}
	
	public void setModelClass(Class<? extends Model> modelClass) {
		this.modelClass = modelClass;
	}
	
	/**
	 * 页面上模型使用的名称
	 * 如果Modelclass是 PubUser ,那么函数返回 pubUser
	 * @return
	 */
	public String getModelSimpleName() {
		if (this.modelSimpleName == null) {
			String modelName = this.getModelClass().getSimpleName();
			modelName = modelName.substring(0, 1).toLowerCase() + modelName.substring(1);
			this.modelSimpleName = modelName;
		}
		
		return modelSimpleName;
	}
	
	/**
	 * 
	 * @return
	 * @throws Exception
	 */
	public Model<?> getModelEntity() throws Exception {
		if (null == modelEntity) {
			modelEntity = (Model<? extends Model>) this.getModel(getModelClass(), this.getModelSimpleName());
		}
		return modelEntity;
	}
	
	/**
	 * <pre>
	 * 拼凑 Model的deleteById 等方法的主键,每个数组里面是一个 主键（或复合主键）
	 * 参数示例 ：
	 * 单主键的../delete?PK=12342134
	 * 复合主键../delete?PK=131241311,fsadfasdf@12324324,fasfasdf
	 * </pre>
	 * @return Object[][] 外层是主键组，内部是主键数组（单主键就一个，复合主键是多个元素的数组）
	 * @throws Exception
	 */
	protected Object[] getPK(String pkPara) throws Exception {
		String temp = StringUtils.trimToNull(pkPara);
		if (temp == null) throw new Exception("请选中至少一条记录");
		
		List<Object> result = new ArrayList<Object>();
		String[] group = temp.split("@");
		for( String pks : group) {
			String[] pksArray = pks.split(",");
			Class<?>[] clsKeys = getPrimaryKey(this.getModelClass());
			
			if (pksArray.length == 1) {
				result.add(instanceKeyByColumnType(clsKeys[0], pksArray[0]));
			} else if (pksArray.length > 1) {
			
				if (pksArray.length != clsKeys.length)
					throw new Exception("传入的主键格式不对");
				
				Object[] keys = new Object[pksArray.length];
				for(int i=0; i<clsKeys.length; i++) {
					keys[i] = instanceKeyByColumnType(clsKeys[i], StringUtils.trimToEmpty(pksArray[i]));
					/*
					if ("java.lang.Long".equals(clsKeys[i].getName())) {
						keys[i] = Long.parseLong(pksArray[i]);
					} else if ( "java.lang.String".equals(clsKeys[i].getName()) ){
						keys[i] = pksArray[i];
					} else if ( "java.lang.Integer".equals(clsKeys[i].getName()) ){
						keys[i] = Integer.parseInt(pksArray[i]);
					} else if ( "java.lang.Short".equals(clsKeys[i].getName()) ){
						keys[i] = Short.parseShort(pksArray[i]);
					} else {
						throw new Exception("不被支持的主键类型");
					}*/
				}
				result.add(keys);
			}
		}
		
		return result.toArray();
	}
	private Object instanceKeyByColumnType(Class<?> type, String value) throws Exception {
		Object result = null;
		if ("java.lang.Long".equals(type.getName())) {
			result = Long.parseLong(value);
		} else if ( "java.lang.String".equals(type.getName()) ){
			result = value;
		} else if ( "java.lang.Integer".equals(type.getName()) ){
			result = Integer.parseInt(value);
		} else if ( "java.lang.Short".equals(type.getName()) ){
			result = Short.parseShort(value);
		} else {
			throw new Exception("不被支持的主键类型");
		}
		return result;
	}
	
	/**
	 * 返回modle类的主键类型(如果是复合主键)
	 * @param modelClass
	 * @return
	 */
	protected Class<?>[] getPrimaryKey(Class<?> mClass) {
		List<Class<?>> result = new ArrayList<Class<?>>();
		Table table = TableMapping.me().getTable((Class<Model>)mClass);
		Map<String, Class<?>> colTypeMap = table.getColumnTypeMap();
		String[] pks = table.getPrimaryKey();
		for(String pk : pks) {
			result.add(colTypeMap.get(pk));
		}
		
		return result.toArray(new Class[pks.length]);
	}
	
	protected String getTableName(Class<?> mClass) {
		Table table = TableMapping.me().getTable((Class<Model>)mClass);
		return table.getName();
	}
	
	/**
	 * <pre>
	 * Example:
	 * "user"     表的主键 "user_id"
	 * "user_role"表的主键 "user_id, role_id"
	 * </pre>
	 * @param mClass
	 * @return  格式 "user_id, role_id"
	 */
	protected String getTablePrimaryKey(Class<?> mClass) {
		Table table = TableMapping.me().getTable((Class<Model>)mClass);
		String str =  Arrays.toString(table.getPrimaryKey());
		return StringUtils.replacePattern(str, "\\[|\\]", "");
	}
	
	
	
}
